java 内置锁 : 每个 java对象 都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。java 内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当 线程A 尝试去获得 线程B 持有的内置锁时,线程A 必须等待或者阻塞,直到 线程B 释放这个锁,如果B线程不释放这个锁,那么 A线程 将永远等待下去
java 对象锁和类锁 : java 的 对象锁 和 类锁 在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的 class对象上的。类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的
类的 非静态方法锁 和 内置锁是同一把锁,也就是都是 对象锁。因此当对象执行到 同步代码块 时这个对象的另外一个线程由于无法获得对象锁因此无法执行这个对象的所有使用 synchronized 修饰的非静态方法
public class TestSynchronized1 {
public void test1() {
synchronized (this) {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
}
public synchronized void test2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
public static void main(String[] args) {
final TestSynchronized1 myt2 = new TestSynchronized1();
Thread test1 = new Thread(myt2::test1, "test1");
Thread test2 = new Thread(myt2::test2, "test2");
test1.start();
test2.start();
// 输出 :
// test1 : 4
// test1 : 3
// test1 : 2
// test1 : 1
// test1 : 0
// test2 : 4
// test2 : 3
// test2 : 2
// test2 : 1
// test2 : 0
}
}
public class TestSynchronized4 {
class Inner {
private void m4t1() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
private synchronized void m4t2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
}
private void m4t1(Inner inner) {
synchronized (inner) {
// 使用对象锁
inner.m4t1();
}
}
private void m4t2(Inner inner) {
inner.m4t2();
}
public static void main(String[] args) {
final TestSynchronized4 myt3 = new TestSynchronized4();
final Inner inner = myt3.new Inner();
Thread t1 = new Thread(() -> myt3.m4t1(inner), "t1");
Thread t2 = new Thread(() -> myt3.m4t2(inner), "t2");
t1.start();
t2.start();
// 输出 :
// t1 : Inner.m4t1()=4
// t1 : Inner.m4t1()=3
// t1 : Inner.m4t1()=2
// t1 : Inner.m4t1()=1
// t1 : Inner.m4t1()=0
// t2 : Inner.m4t2()=4
// t2 : Inner.m4t2()=3
// t2 : Inner.m4t2()=2
// t2 : Inner.m4t2()=1
// t2 : Inner.m4t2()=0
}
}
静态方法锁 就是 类锁
public class TestSynchronized2 {
public void test1() {
synchronized (TestSynchronized2.class) {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
}
public static synchronized void test2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
public static void main(String[] args) {
final TestSynchronized2 myt2 = new TestSynchronized2();
Thread test1 = new Thread(myt2::test1, "test1");
Thread test2 = new Thread(TestSynchronized2::test2, "test2");
test1.start();
test2.start();
// 输出 :
// test1 : 4
// test1 : 3
// test1 : 2
// test1 : 1
// test1 : 0
// test2 : 4
// test2 : 3
// test2 : 2
// test2 : 1
// test2 : 0
}
}
类锁 和 对象锁不是通一把锁,相互之间互不干扰
public class TestSynchronized3 {
public synchronized void test1() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
public static synchronized void test2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
public static void main(String[] args) {
final TestSynchronized3 myt2 = new TestSynchronized3();
Thread test1 = new Thread(myt2::test1, "test1");
Thread test2 = new Thread(TestSynchronized3::test2, "test2");
test1.start();
test2.start();
// 输出 :
// test1 : 4
// test2 : 4
// test2 : 3
// test1 : 3
// test2 : 2
// test1 : 2
// test2 : 1
// test1 : 1
// test1 : 0
// test2 : 0
}
}
此处会先输出 showA.. showC.. 等待 3秒后再输出 showB..,可以使用 synchronized 代码块或方法只有获取到响应的锁之后才能执行相应的方法
public class TestSynchronized5 {
public synchronized void showA() {
System.out.println("showA..");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void showB() {
synchronized (this) {
System.out.println("showB..");
}
}
public void showC() {
String s = "1";
synchronized (s) {
System.out.println("showC..");
}
}
public static void main(String[] args) {
final TestSynchronized5 sy = new TestSynchronized5();
new Thread(sy::showA).start();
new Thread(sy::showB).start();
new Thread(sy::showC).start();
// 输出 :
// showA..
// showC..
// showB..
}
}
1> 当两个并发线程访问同一个对象 object 中的这个 synchronized(this) 同步代码块时,一个时间内只能有一个线程得到执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
2> 然而,当一个线程访问 object 的一个 synchronized(this) 同步代码块时,另一个线程仍然可以访问该 object 中的非synchronized(this)同步代码块
3> 尤其关键的是,当一个线程访问object的一个 synchronized(this) 同步代码块时,其他线程对 object 中所有其它 synchronized(this) 同步代码块 或 synchronized 修饰的非静态方法 的访问将被阻塞
4> 对象锁和类锁可以同时获得,即两种方法可以同时运行,互不影响
5> 一种锁方法只能运行同时运行一个,同种其他的锁方法暂时阻塞,普通方法的运行不受限制